# coding:UTF-8
import cv2  
import numpy as np  
from skimage import draw
import math
import datetime
import time


class Detect:
    def __init__(self, path):
        self.ori_img = path
        self.gray = cv2.cvtColor(self.ori_img, cv2.COLOR_BGR2GRAY)
        self.hsv = cv2.cvtColor(self.ori_img, cv2.COLOR_BGR2HSV)
        # 获得原始图像行列
        rows, cols = self.ori_img.shape[:2]

        # 工作图像
        self.work_img = cv2.resize(
            self.ori_img, (int(cols / 4)*5, int(rows / 4)*5))
        self.work_gray = cv2.resize(
            self.gray, (int(cols / 4)*5, int(rows / 4)*5))
        self.work_hsv = cv2.resize(
            self.hsv, (int(cols / 4)*5, int(rows / 4)*5))

    # 颜色区域提取
    def color_area(self):
        # 提取红色区域(暂定框的颜色为红色)
        low_red1 = np.array([0, 43, 46])
        high_red1 = np.array([8, 255, 255])
        # 将低于lower_red和高于upper_red的部分分别变成0，lower_red～upper_red之间的值变成255
        mask1 = cv2.inRange(self.work_hsv, low_red1, high_red1)
        sum1 = np.sum(mask1)

        low_red2 = np.array([156, 43, 46])
        high_red2 = np.array([180, 255, 255])
        # 将低于lower_red和高于upper_red的部分分别变成0，lower_red～upper_red之间的值变成255
        mask2 = cv2.inRange(self.work_hsv, low_red2, high_red2)
        sum2 = np.sum(mask2)

        if sum1>sum2:
            mask = mask1
        else:
            mask = mask2

        red = cv2.bitwise_and(self.work_hsv, self.work_hsv, mask=mask)
        return red  # 变成黑白图片
 
    # 形态学处理
    def good_thresh_img(self, img):
        # hsv空间变换到gray空间
        img = cv2.cvtColor(img, cv2.COLOR_HSV2BGR)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 阈值处理
        _, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
        # 做一些形态学操作,去一些小物体干扰

        se = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))

        img_morph = cv2.dilate(thresh, se)
        img_morph = cv2.erode(img_morph, se)
        img_morph = cv2.erode(img_morph, se, iterations=1)
        img_morph = cv2.dilate(img_morph, se, iterations=1)

        return img_morph #处理后的图片黑白分明，效果明显更优

    '''
    ＠params img:目标图片，需要找到指定轮廓的图片
    ＠return 第一个值：四个关键轮廓点
            第二个值：形成的目标轮廓的最小宽度
            第三个值：标记值，避免排序时cnts为空，程序异常终止
    '''
    # 矩形四角点提取
    def key_points_tap(self, img):
        img_cp = img.copy()
        # 按结构树模式找所有轮廓
        aa,cnts, _ = cv2.findContours(img_cp, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        # 按区域大小排序,找到第二大轮廓
        if len(cnts) == 0:
            return -1,0,0
        else:
            cnt_second = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
            # 找轮廓的最小外接矩形((point), (w, h))
            box = cv2.minAreaRect(cnt_second)
            width = box[1][0]
            return np.intc(cv2.boxPoints(box)),width,1

    # 画出关键轮廓的最校外接矩形
    def key_cnt_draw(self, points):
        mask = np.zeros(self.work_gray.shape, np.uint8)

        cv2.drawContours(self.work_img, [points], -1, 255, 2)
        return mask

    def distance(self, points):
        # 得到图像中心
        rows, cols = self.work_img.shape[:2]
        img_center_x, img_center_y = cols / 2, rows / 2

        distance = 0
        for i in range(0, len(points)):
            a, b = points[i, :2]
            now_distance = np.sqrt(
                np.square(a - img_center_x) + np.square(b - img_center_y))
            if i == 0:
                distance = now_distance
                key_x = a
                key_y = b
            elif now_distance < distance:
                distance = now_distance
                key_x = a
                key_y = b
            else:
                print('no change')
        return distance, key_x, key_y
    '''
    @params width:物体在图片中的像素宽度
    @params gap:物体离图片中心的距离
    @return distance:实际距离,单位：cm
    @return result:实际角度,稍有偏差
    '''
    def get_Angle_Distance(self, width, gap):
        #distance是希望实际测试像素宽度，实际距离之间的关系所得到的公式，此处不准
        distance = -(1/8) * width + 75
        key = 10 * gap / width    #此处将物体的实际长度定成１０cm,key是实际物体离相机中心轴的水平距离
        #此处角度暂未对值的情况进行选择性判断，需要最终确定后再改
        # angle = math.acos(key / distance)
        angle = math.acos(16 / 25)
        result = angle * 180 /math.pi
        return distance,result

    # 运行主函数
    def img_process_main(self,count):
        # start = datetime.datetime.now()
        # 找到红色区域
        red = self.color_area()
        # 处理得到一个比较好的二值图
        img_morph = self.good_thresh_img(red)
        # 获取矩形框的四个关键点
        points, width, flag= self.key_points_tap(img_morph)
        if flag == 1:
            distance = self.distance(points)
            print('图片中物体的像素宽度：',width)
            cnt_img = self.key_cnt_draw(points)
            cv2.drawContours(self.ori_img, [points], -1, 255, 1)

            length,angle = self.get_Angle_Distance(width,distance[0])
            print('length:',length)
            print('angle:',angle)
            text = 'length:' + str(round(length,2)) +" "+'angle:' + str(round(angle,2))
            cv2.putText(self.work_img, text, (40, 50), cv2.FONT_HERSHEY_PLAIN, 2.0, (0, 0, 255), 2)
            # 显示图像        
            cv2.imshow('ori', self.work_img)
            return length,angle
        else:
            cv2.imshow('ori',self.work_img)
            return 'error','error'
        # cv2.imwrite('./img/'+str(count) + '.jpg',self.work_img) #存储为图像

        # print(self.work_img.shape)

        # end = datetime.datetime.now()
        # time = (end - start).microseconds
        # print('time',time)


if __name__ == '__main__':
    root_path = './img'    #实际图片存放的位置
    img_path = root_path + '/' + str(500) + '.jpg'
    d = Detect(img_path)
    # start = datetime.datetime.now()
    d.img_process_main()
    # end = datetime.datetime.now()
    # print((start-end).seconds)
